package dev.ece.suit.loader.models.fbx;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;

import dev.ece.util.io.LittleEndianInputStream;

public class FBXElement {

	private String id;
	
	private FBXProperty[] properties;
	
	private FBXElement[] children;
	
	private FBXElement() {}
	
	public FBXElement findFirstChild(String id) {
		if(hasChildren()) {
			for(FBXElement child: children) {
				if(StringUtils.equals(child.getId(), id)) {
					return child;
				}
			}
		}
		return null;
	}
	
	public FBXElement[] findChildren(String id) {
		List<FBXElement> list = new ArrayList<FBXElement>();
		if(hasChildren()) {
			for(FBXElement child: children) {
				if(StringUtils.equals(child.getId(), id)) {
					list.add(child);
				}
			}
		}
		return list.toArray(new FBXElement[] {});
	}
	
	public Map<String, List<FBXElement>> toFBXElementMap() {
		Map<String, List<FBXElement>> map = new ConcurrentHashMap<String, List<FBXElement>>();
		if(hasChildren()) {
			List<FBXElement> list = null;
			for(FBXElement child: children) {
				list = map.get(child.getId());
				if(list == null) {
					list = new ArrayList<FBXElement>();
					map.put(child.getId(), list);
				}
				list.add(child);
			}
		}
		return map;
	}
	
	public boolean hasProperties() {
		return getProperties() != null && getProperties().length > 0;
	}
	
	public boolean hasChildren() {
		return getChildren() != null && getChildren().length > 0;
	}
	
	public static Map<String, FBXElement> loadFBXElements(LittleEndianInputStream input, FBXHeader header) throws IOException {
		Map<String, FBXElement> result = new ConcurrentHashMap<String, FBXElement>();
		FBXElement element = null;
		while((element = loadFBXElement(input, header)) != null) {
			result.put(element.getId(), element);
		}
		return result;
	}
	
	public static FBXElement loadFBXElement(LittleEndianInputStream input, FBXHeader header) throws IOException {
		long endOffset = header.readElementOffset(input);
		if(endOffset < 1) {
			return null;
		}
		FBXElement element = new FBXElement();
		long prop_count = header.readElementOffset(input);
		//prop_length
		header.readElementOffset(input);
		element.id = input.readString(input.readByte());
		element.properties = new FBXProperty[(int) prop_count];
		for(int i=0; i<prop_count; i++) {
			element.properties[i] = FBXProperty.loadFBXProperty(input);
		}
		if(input.position() < endOffset) {
			int blockSentinelLength = header.blockSentinelLength();
			long offset =  endOffset - blockSentinelLength;
			FBXElement child = null;
			List<FBXElement> children = new ArrayList<FBXElement>();
			while(input.position() < offset) {
				child = loadFBXElement(input, header);
				if(child != null) {
					children.add(child);
				}
			}
			element.children = children.toArray(new FBXElement[] {});
			input.skip(blockSentinelLength);
		}
		return element;
	}

	public String getId() {
		return id;
	}

	public FBXProperty[] getProperties() {
		return properties;
	}

	public FBXElement[] getChildren() {
		return children;
	}

	public void setChildren(FBXElement[] children) {
		this.children = children;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("(id=").append(this.getId()).append("\n");
		if(this.hasChildren()) {
			builder.append("children=[");
			for(FBXElement child: children) {
				builder.append(child.toString());
			}
			builder.append("]");
		}
		if(this.hasProperties()) {
			builder.append("properties=[");
			for(FBXProperty property: properties) {
				builder.append(property.toString());
			}
			builder.append("]\n");
		}
		builder.append(")");
		return builder.toString();
	}

}
